Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSDK-9839: Have Go module clients be webrtc aware. #4751

Merged
merged 3 commits into from
Feb 5, 2025

Conversation

dgottlieb
Copy link
Member

No description provided.

@viambot viambot added the safe to test This pull request is marked safe to test from a trusted zone label Jan 28, 2025
@dgottlieb dgottlieb requested a review from benjirewis January 30, 2025 19:28
Copy link
Member

@benjirewis benjirewis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think some other changes to grpc/shared_conn.go and a couple other files slipped into here from the last version I saw?

I'll probably need a brief synchronous meeting to understand what's happening with the NewSharedConnForModule function and some of the peer connection grabbing and setting. Or you can definitely bypass my review and get @nicksanford's or someone with more context. Up to you!

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Jan 31, 2025
peerConnMu sync.Mutex
peerConn *webrtc.PeerConnection
peerConnReady <-chan struct{}
peerConnClosed <-chan struct{}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was unused


ret.peerConn.OnTrack(func(trackRemote *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) {
sid := trackRemote.StreamID()
if sid == "rtsp-1" {
Copy link
Member Author

@dgottlieb dgottlieb Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicksanford , we need to do a real thing here. Not sure if the logic to put here is simple enough to communicate over a PR or if syncing in person would yield a better answer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets sync in person about this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
logger := rc.Logger().Sublogger(resource.RemoveRemoteName(name).ShortName())
return apiInfo.RPCClient(rc.backgroundCtx, &rc.conn, rc.remoteName, name, logger)
return apiInfo.RPCClient(rc.backgroundCtx, rc.getClientConn(), rc.remoteName, name, logger)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For @benjirewis 's edification, this is the thing we pass into the (camera) client constructor. Having this (newly added) getClientConn to return a SharedConn when (also new added) SetPeerConnection was called is what allows this "camera client.PeerConn" call to return a non-nil value.

It's certainly the intention that only module programs go through this code path (due to calling SetPeerConnection). And it's the intention that clients that never look at "clientConn.PeerConn" behave exactly the same (everything is funneled over the grpc.Dial("unix socker")).

What's probably a better change (but a bit more movement/copying/uncertainty), that we can iterate towards, is having module/module.go avoid calling "robotClient.ResourceByName". Such that we don't need to expose this RobotClient.SetPeerConnection method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that vaguely makes sense to me.

What's probably a better change (but a bit more movement/copying/uncertainty), that we can iterate towards, is having module/module.go avoid calling "robotClient.ResourceByName".

I suppose we've been treating the module -> rdk client connection as a regular Golang SDK client, but I can see it's now diverging slightly. I don't have as much context as you, but I might push to continue to use ResourceByName unless you find that the module -> rdk gRPC client creation is more and more distinct from regular gRPC client creation. Just so we don't have to maintain two different gRPC client creation paths.

Copy link
Member Author

@dgottlieb dgottlieb Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we've been treating the module -> rdk client connection as a regular Golang SDK client

Well, our other option is to use gRPC over WebRTC for the module connections in which case this would work without modifications! Once we moved to webrtc and used its video tracks, rdk client behavior started to diverge.

This patch shoves that detail of how module connections are special into the robot Client. But by just calling (or not calling) SetPeerConnection. The only reason I prefer to not litter robot client with that detail is because of the whole "it's part of the public interface" for applications. I don't think I'd have an opinion if the two kinds of clients were distinct.

@@ -193,7 +232,7 @@ func (sc *SharedConn) ResetConn(conn rpc.ClientConn, moduleLogger logging.Logger
}

sc.peerConn = peerConn
sc.peerConnReady, sc.peerConnClosed, err = rpc.ConfigureForRenegotiation(peerConn, rpc.PeerRoleClient, sc.logger)
sc.peerConnReady, _, err = rpc.ConfigureForRenegotiation(peerConn, rpc.PeerRoleServer, sc.logger)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to double check if we need PeerRoleServer or Client. And I ought to document the consequence of this choice.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed this is in fact needed.

@dgottlieb
Copy link
Member Author

@benjirewis, I've redone this PR to officially be on top of what we just merged. And you're right that @nicksanford is a better candidate for the SharedConn changes.

Your PR Benji can be scoped down to the module and robot client changes. I left a more detailed note on the diff.

@dgottlieb dgottlieb requested a review from nicksanford January 31, 2025 14:31
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Jan 31, 2025
Copy link
Member

@benjirewis benjirewis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM % Nick's review.

@@ -680,10 +688,10 @@ func (rc *RobotClient) ResourceByName(name resource.Name) (resource.Resource, er
func (rc *RobotClient) createClient(name resource.Name) (resource.Resource, error) {
apiInfo, ok := resource.LookupGenericAPIRegistration(name.API)
if !ok || apiInfo.RPCClient == nil {
return grpc.NewForeignResource(name, &rc.conn), nil
return grpc.NewForeignResource(name, rc.getClientConn()), nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a comment at the top of the getClientConn method that says: // Must be called with rc.mu in ReadLock+ mode. Are we doing that here? I assume the lock is already before we call createClient?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
logger := rc.Logger().Sublogger(resource.RemoveRemoteName(name).ShortName())
return apiInfo.RPCClient(rc.backgroundCtx, &rc.conn, rc.remoteName, name, logger)
return apiInfo.RPCClient(rc.backgroundCtx, rc.getClientConn(), rc.remoteName, name, logger)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that vaguely makes sense to me.

What's probably a better change (but a bit more movement/copying/uncertainty), that we can iterate towards, is having module/module.go avoid calling "robotClient.ResourceByName".

I suppose we've been treating the module -> rdk client connection as a regular Golang SDK client, but I can see it's now diverging slightly. I don't have as much context as you, but I might push to continue to use ResourceByName unless you find that the module -> rdk gRPC client creation is more and more distinct from regular gRPC client creation. Just so we don't have to maintain two different gRPC client creation paths.


ret.peerConn.OnTrack(func(trackRemote *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) {
sid := trackRemote.StreamID()
if sid == "rtsp-1" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets sync in person about this


ret.peerConn.OnTrack(func(trackRemote *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) {
sid := trackRemote.StreamID()
if sid == "rtsp-1" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -268,6 +275,7 @@ func New(ctx context.Context, address string, clientLogger logging.ZapCompatible
sessionsDisabled: rOpts.disableSessions,
heartbeatCtx: heartbeatCtx,
heartbeatCtxCancel: heartbeatCtxCancel,
isModuleConnection: rOpts.modName != "",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where isModuleConnection is used. Do we intend to use this in an upcoming PR? If so, how?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that. That was a leftover from hacking that I decided not to use, but missed in the cleanup.

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 3, 2025
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 4, 2025
//
// Modules talking back to the viam-server for a camera stream should use the "short
// name"/`SDPTrackName` (i.e: `foo`).
if sc, ok := c.conn.(*grpc.SharedConn); ok && sc.IsConnectedToModule() {
Copy link
Member Author

@dgottlieb dgottlieb Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic change for knowing when to use a full resource name

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 4, 2025
}

// IsConnectedToModule returns whether this shared conn is being used to communicate with a module.
func (sc *SharedConn) IsConnectedToModule() bool {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created two methods for this because I didn't think it was obvious this was indeed binary? And I like to read these descriptions in the affirmative tense

@dgottlieb dgottlieb requested a review from nicksanford February 4, 2025 21:30
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 5, 2025
@dgottlieb dgottlieb merged commit 3ed3cc1 into viamrobotics:main Feb 5, 2025
16 checks passed
@dgottlieb dgottlieb deleted the RSDK-9839 branch February 5, 2025 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
safe to test This pull request is marked safe to test from a trusted zone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants